<!DOCTYPE html>
<meta charset="utf-8" />
<title>WebSocket Test</title>
<script src="https://cdn.rawgit.com/dcodeIO/protobuf.js/6.8.8/dist/protobuf.min.js"></script>

<script language="javascript" type="text/javascript">


var wsUri = "ws://localhost:9002";
var output;
var proto = "syntax = \"proto3\";\
  package gz.msgs;\
  message Time {\
    int64 sec = 1;\
    int32 nsec = 2;\
  }\
  message Clock\
  {\
    Header header = 1;\
    Time system = 2;\
    Time real   = 3;\
    Time sim    = 4;\
  }\
  message Header {\
    message Map {\
      string key = 1;\
      repeated string value = 2;\
    }\
    Time stamp         = 1;\
    repeated Map data  = 2;\
  }\
  message WebRequest\
  {\
    Header header         = 1;\
    string operation      = 2;\
    string topic          = 3;\
    string msg_type       = 4;\
    string compression    = 5;\
    double hz             = 6;\
  }\
  message StringMsg_V\
  {\
    repeated string data = 2;\
  }\
  message CmdVel2D\
  {\
    Header header    = 1;\
    double velocity  = 2;\
    double theta     = 3;\
  }\
  enum PixelFormatType\
  {\
    UNKNOWN_PIXEL_FORMAT = 0;\
    L_INT8 = 1;\
    L_INT16 = 2;\
    RGB_INT8 = 3;\
    RGBA_INT8 = 4;\
    BGRA_INT8 = 5;\
    RGB_INT16 = 6;\
    RGB_INT32 = 7;\
    BGR_INT8 = 8;\
    BGR_INT16 = 9;\
    BGR_INT32 = 10;\
    R_FLOAT16 = 11;\
    RGB_FLOAT16 = 12;\
    R_FLOAT32 = 13;\
    RGB_FLOAT32 = 14;\
    BAYER_RGGB8 = 15;\
    BAYER_RGGR8 = 16;\
    BAYER_GBRG8 = 17;\
    BAYER_GRBG8 = 18;\
  }\
  \
  message Image\
  {\
    Header header        = 1;\
    uint32 width         = 2;\
    uint32 height        = 3;\
    uint32 pixel_format  = 4;\
    uint32 step          = 5;\
    bytes data          = 6;\
  }\
  message Vector3d\
  {\
    Header header = 1;\
    double x = 2;\
    double y = 3;\
    double z = 4;\
  }\
  message Pose\
  {\
    Header header          = 1;\
    string name            = 2;\
    uint32 id              = 3;\
    Vector3d position      = 4;\
    Quaternion orientation = 5;\
  }\
  message Quaternion\
  {\
    Header header = 1;\
    double x = 2;\
    double y = 3;\
    double z = 4;\
    double w = 5;\
  }\
  message Double_V\
  {\
    repeated double data = 1;\
  }\
  message Pose_V\
  {\
    Header header = 1;\
    repeated Pose pose = 2;\
  }\
  message Packet\
  {\
    string topic = 1;\
    string type  = 2;\
  \
    oneof content\
    {\
      CmdVel2D cmd_vel2d = 3;\
      Image image = 4;\
      StringMsg_V string_msg_v = 5;\
      WebRequest web_request = 6;\
      Pose pose = 7;\
      Double_V doublev = 8;\
      Pose_V pose_v = 9;\
      Time time = 10;\
      Clock clock = 11;\
    }\
  }";

var root = protobuf.parse(proto, {keepCase: true}).root;

var websocket;

function init()
{
  output = document.getElementById("output");

  wsConnect();
}

function wsConnect()
{
  const disconnect = document.getElementById('disconnect').checked;
  if (websocket !== undefined && disconnect) {
    console.log('closing!\n');
    websocket.close();
  }
  websocket = new WebSocket(wsUri);
  websocket.onopen = function(evt) { onOpen(evt) };
  websocket.onclose = function(evt) { onClose(evt) };
  websocket.onmessage = function(evt) { onMessage(evt) };
  websocket.onerror = function(evt) { onError(evt) };
}

function wsDisconnect() {
  if (websocket !== undefined) {
    websocket.close();
  }
}

function wsSubscribe(topic = "/world/shapes/pose/info") {
  var requestType = root.lookupType("WebRequest");
  var webRequestMsg = requestType.encode({
    operation: "subscribe",
    topic,
    compression: "none",
  }).finish();
  doSend(webRequestMsg);
}

function onOpen(evt)
{
  writeToScreen("CONNECTED");
  var msgType = root.lookupType("WebRequest");
  var webRequestMsg = msgType.encode({
    operation: "list",
    compression: "none",
  }).finish();
  doSend(webRequestMsg);
}

function onClose(evt)
{
  writeToScreen("DISCONNECTED");
}

function onMessage(evt)
{

  var f = new FileReader();
  f.onloadend = function(event) {
    var contents = event.target.result;
    // Decode the message. We are assuming it's a string message....
    var msgType = root.lookupType("Packet");
    var msg = msgType.decode(new Uint8Array(contents));
    // writeToScreen('<span style="color: blue;">RESPONSE: ' +
    //  JSON.stringify(msg.toJSON()) +'</span>');

    if (msg.content !== undefined) {
      if (msg.content === "string_msg_v") {
        // Subscribe to the first topic.
        // The topics arrive here.
        // Uncomment to subscribe to one as a response to the connection.
        // wsSubscribe();
      } else if (msg.content === "pose_v") {

        msg_output = document.getElementById("msg_output");
        msg_output.innerHTML = JSON.stringify(msg.pose_v.toJSON());
        /*
        writeToScreen('<span style="color: blue;"> ' +
        +'</span>');
        */
      }
    }
  }
  f.readAsArrayBuffer(evt.data);
}

function onError(evt)
{
  writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}

function doSend(message)
{
  websocket.send(message);
}

function writeToScreen(message)
{
  var pre = document.createElement("p");
  pre.style.wordWrap = "break-word";
  pre.innerHTML = message;
  output.appendChild(pre);
}

window.addEventListener("load", init, false);

</script>

<h2>WebSocket Test</h2>

<div>
  <button onclick="wsConnect()">Connect</button>
  <button onclick="wsDisconnect()">Disconnect</button>
  <button onclick="wsSubscribe()">Subscribe</button>
<div>

<ul>
  <li>By default, the Client will always have just <em>one</em> websocket connection. The Connect button closes the previous websocket.</li>
  <li>The Server keeps track of the connections. If we open a new websocket without closing the old one, they will pile up on the Server.</li>
</ul>

<input type="checkbox" id="disconnect" name="disconnect" checked>
<label for="disconnect">Uncheck if you don't want to disconnect on new connections (for testing purposes)</label>

<p>
  When you click the Subscribe button, you'll receive messages from the Server.
</p>

<div id="output">
</div>

<div id='msg_output'></div>
